#include "sys_spi.h"
#include "sys_types.h"
#include "sys_uart.h"
#include "sys_interrupt.h"
#include "sys_delay.h"
#include "sys_gpio.h"
#include "sys_io.h"
#include "sys_cache.h"

// 默认最大时钟频率
#define SPI_MAX_CLK_HZ (60000000)
/*DMA使能时需要使用到内存分配，如果有使用系统,不能使用C库的malloc,请使用固定内存分配或系统的内存管理*/
#ifdef __SPI_DMA_EN // SPI DMA使能
#define SPI_DMA_EN 1
#endif
/*---------------------------------------------------
修改记录
2020-04-13
	1.128x512字节写不正常，sys_spi.c中SPI_Flash_Write函数的参数unsigned short NumByteToWrite改为unsigned int NumByteToWrite
2020-08-19
	1.增加DMA读写模式
2020-12-17
	1.增加32K块，64K块擦除函数
	2.增加读UID(唯一ID),设备ID函数
2021-06-10
	1.DMA与中断开启的情况读写失败：增加一个虚拟缓存virtual_buff替换读写函数的NULL代入参数。
2021-07-07
	1.virtual_buff改为使用malloc分配，如果有使用系统,不能使用C库的malloc,请使用固定内存分配或系统的内存管理。
2021-07-09
	1.增加对16MB以上型号读写的支持,主要增加进入4地址模式与4地址读写-W25Q256测试正常。
2021-07-14
	1.增加对CLK的频率限制与最大频率设置函数,避免频率太高而读写错误问题。


----------------------------------------------------*/

#if SPI_DMA_EN
#include "sys_dma.h"
#include "stdlib.h"
void *spi_malloc(size_t size)
{
	void *p = malloc(size);
	if (((int)p % 4) != 0) // DMA缓存需要4字节对齐
	{
		sysprintf("ERR:spi_malloc() alignment(%08x)\r\n", p);
		free(p);
		return 0;
	}
	return p;
}
void spi_free(void *p)
{
	free(p);
}
#endif

#define spi_get_addr(x) (0x01C05000 + x * 0x1000) // 返回SPI地址

#if SPI_DMA_EN
DMA *SPI_TXdma;
DMA *SPI_RXdma;
#endif

enum
{
	SPI_GCR = 0x04,
	SPI_TCR = 0x08,
	SPI_IER = 0x10,
	SPI_ISR = 0x14,
	SPI_FCR = 0x18,
	SPI_FSR = 0x1c,
	SPI_WCR = 0x20,
	SPI_CCR = 0x24,
	SPI_MBC = 0x30,
	SPI_MTC = 0x34,
	SPI_BCC = 0x38,
	SPI_TXD = 0x200,
	SPI_RXD = 0x300,
};

// HZ 最大时钟限制
int spi_max_clk = SPI_MAX_CLK_HZ;
void set_max_clk(int clk)
{
	spi_max_clk = clk;
}
/*---------------------------------------------------
SPI DMA传输时的等待->多任务时可执行其它任务
---------------------------------------------------*/
void spi_dma_delay(void)
{
	// delay_ms(1);
}
/*---------------------------------------------------
SPI配置
---------------------------------------------------*/
void spi_spi_confing(int SPI)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	u32_t val;

	/*
	if CPU_CLK=600MHZ
	AHB_CLK=CPU_CLK/2=600/2=300
	SPI_CLK=AHB_CLK / (2*(n + 1));
	[n=2 SPI_CLK=50MHZ]
	[n=1 SPI_CLK=75MHZ]
	[n=0 SPI_CLK=150MHZ]
	*/

	/*
	if CPU_CLK=408MHZ
	AHB_CLK=CPU_CLK/2=408/2=204
	SPI_CLK=AHB_CLK / (2*(n + 1));


  [n=5 SPI_CLK=17MHZ]
	[n=4 SPI_CLK=20.4MHZ]
	[n=3 SPI_CLK=25.5MHZ]
	[n=2 SPI_CLK=34MHZ]
	[n=1 SPI_CLK=51MHZ]
	[n=0 SPI_CLK=102MHZ]
	*/
	int n = 0;
	int ahb_clk = get_ahb_frequency();
	while (n < 10)
	{
		int spi_clk = ahb_clk / (2 * (n + 1));
		if (spi_clk > spi_max_clk) // SPI 时钟频率限制
		{
			sysprintf("SPI%d CLK SET.\r\n", SPI, n);
			n++;
		}
		else
		{
			sysprintf("SPI%d CLK[%dHZ]...\r\n", SPI, spi_clk);
			break;
		}
	}
	/* Set spi clock rate control register, divided by 4 */
	write32(addr + SPI_CCR, 0x00001000 | n);

	/* Enable spi and do a soft reset */
	val = read32(addr + SPI_GCR);
	val |= ((u64_t)1 << 31) | (1 << 7) | (1 << 1) | (1 << 0);
	write32(addr + SPI_GCR, val);
	while (read32(addr + SPI_GCR) & ((u64_t)1 << 31))
		;

	val = read32(addr + SPI_TCR);
	val &= ~(0x3 << 0);
	val |= (1 << 6) | (1 << 2);
	write32(addr + SPI_TCR, val);

	val = read32(addr + SPI_FCR);
	val |= ((u64_t)1 << 31) | (1 << 15);
	write32(addr + SPI_FCR, val);
}

/*---------------------------------------------------
SPI开CS
---------------------------------------------------*/
void sys_spi_select(int SPI)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	u32_t val;

	val = read32(addr + SPI_TCR);
	val &= ~((0x3 << 4) | (0x1 << 7));
	val |= ((0 & 0x3) << 4) | (0x0 << 7);
	write32(addr + SPI_TCR, val);
}
/*---------------------------------------------------
SPI关CS
---------------------------------------------------*/
void sys_spi_deselect(int SPI)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	u32_t val;

	val = read32(addr + SPI_TCR);
	val &= ~((0x3 << 4) | (0x1 << 7));
	val |= ((0 & 0x3) << 4) | (0x1 << 7);
	write32(addr + SPI_TCR, val);
}
/*---------------------------------------------------
SPI写
---------------------------------------------------*/
static void sys_spi_write_txbuf(int SPI, u8_t *buf, int len)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	int i;

	if (!buf)
		len = 0;

	write32(addr + SPI_MTC, len & 0xffffff);
	write32(addr + SPI_BCC, len & 0xffffff);
	for (i = 0; i < len; ++i)
		write8(addr + SPI_TXD, *buf++);
}
/*---------------------------------------------------
使能DMA_DRQ
---------------------------------------------------*/
void sys_spi_enable_drq(int SPI, int tx_drq_en, int rx_drq_en)
{
	virtual_addr_t addr = spi_get_addr(SPI);

	if (tx_drq_en == 0)
		C_BIT(addr + SPI_FCR, 24); // TX_DRQ
	else
		S_BIT(addr + SPI_FCR, 24);

	if (rx_drq_en == 0)
		C_BIT(addr + SPI_FCR, 8); // RX_DRQ
	else
		S_BIT(addr + SPI_FCR, 8);
}
/*---------------------------------------------------
设置计数值
---------------------------------------------------*/
void sys_spi_set_count(int SPI, int count)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	write32(addr + SPI_MBC, count & 0xffffff);
	write32(addr + SPI_MTC, count & 0xffffff);
	write32(addr + SPI_BCC, count & 0xffffff);
}
/*---------------------------------------------------
SPI开始
---------------------------------------------------*/
void sys_spi_start(int SPI)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	S_BIT(addr + SPI_TCR, 31);
}
/*---------------------------------------------------
SPI SPI CPU传输
----------------------------------------------------*/
static int sys_spi_cpu_transfer(int SPI, void *txbuf, void *rxbuf, int len)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	int count = len;
	u8_t *tx = txbuf;
	u8_t *rx = rxbuf;
	u8_t val;
	int n, i;
	while (count > 0)
	{
		n = (count <= 64) ? count : 64;
		write32(addr + SPI_MBC, n);
		sys_spi_write_txbuf(SPI, tx, n);
		write32(addr + SPI_TCR, read32(addr + SPI_TCR) | ((u64_t)1 << 31));

		while ((read32(addr + SPI_FSR) & 0xff) < n)
			;

		for (i = 0; i < n; i++)
		{
			val = read8(addr + SPI_RXD);
			if (rx)
				*rx++ = val;
		}
		if (tx)
			tx += n;
		count -= n;
	}
	return len;
}
#if SPI_DMA_EN
/*---------------------------------------------------
SPI DMA transfe
----------------------------------------------------*/
int sys_spi_dma_transfer(int SPI, DMA *TXdma, DMA *RXdma, void *txbuf, void *rxbuf, int len)
{
	virtual_addr_t addr = spi_get_addr(SPI);
	//---------
	TXdma->Type = NDMA;					 // 类型
	TXdma->Ch = 0;						 // 通道
	TXdma->Byte_Counter = len;			 // Byte计数
	TXdma->Continuous_Mode_Enable = 0;	 // 连续模式
	TXdma->Read_Byte_Counter_Enable = 0; // 读计数值使能
	//---------
	TXdma->Source_Address = (unsigned int)txbuf;		  // 源地址
	TXdma->Source_Address_Type = DMA_ADDRESS_TYEP_LINEER; // 源地址类型
	TXdma->Source_DRQ_Type = NDMAS_DRQ_Type_SDRAM_Memory; // 源类型
	TXdma->Source_Data_Width = DMA_DATA_WIDTH_8;		  // 源数据宽度
	TXdma->Source_Burst_Length = DMA_BURST_LENGTH_1;	  // BURST
	//-----------
	TXdma->Destination_Address = (unsigned int)(addr + SPI_TXD);								// 目标地址
	TXdma->Destination_Address_Type = DMA_ADDRESS_TYEP_IO;										// 目标地址类型
	TXdma->Destination_DRQ_Type = (SPI == 0 ? NDMAD_DRQ_Type_SPI0_Tx : NDMAD_DRQ_Type_SPI1_Tx); // 目标类型
	TXdma->Destination_Data_Width = DMA_DATA_WIDTH_8;											// 目标数据宽度
	TXdma->Destination_Burst_Length = DMA_BURST_LENGTH_1;										// BURST
	//-----------
	//	sysprintf("发送数据大小: %d \r\n",TXdma->Byte_Counter);
	DMA_Config(TXdma);
	DMA_Enable(TXdma);

	//---------------------------------------------------------------------------------------
	RXdma->Type = NDMA;					 // 类型
	RXdma->Ch = 1;						 // 通道
	RXdma->Byte_Counter = len;			 // Byte计数
	RXdma->Continuous_Mode_Enable = 0;	 // 连续模式
	RXdma->Read_Byte_Counter_Enable = 0; // 读计数值使能
	//---------
	RXdma->Source_Address = (unsigned int)(addr + SPI_RXD);								   // 源地址
	RXdma->Source_Address_Type = DMA_ADDRESS_TYEP_IO;									   // 源地址类型
	RXdma->Source_DRQ_Type = (SPI == 0 ? NDMAS_DRQ_Type_SPI0_Rx : NDMAS_DRQ_Type_SPI1_Rx); // 源类型
	RXdma->Source_Data_Width = DMA_DATA_WIDTH_8;										   // 源数据宽度
	RXdma->Source_Burst_Length = DMA_BURST_LENGTH_1;									   // BURST
	//-----------
	RXdma->Destination_Address = (unsigned int)rxbuf;		   // 目标地址
	RXdma->Destination_Address_Type = DMA_ADDRESS_TYEP_LINEER; // 目标地址类型
	RXdma->Destination_DRQ_Type = NDMAD_DRQ_Type_SDRAM_Memory; // 目标类型
	RXdma->Destination_Data_Width = DMA_DATA_WIDTH_8;		   // 目标数据宽度
	RXdma->Destination_Burst_Length = DMA_BURST_LENGTH_1;	   // BURST
	//-----------
	// sysprintf("接收数据大小: %d \r\n",RXdma->Byte_Counter);
	DMA_Config(RXdma);
	DMA_Enable(RXdma);

	// 设置计数值
	sys_spi_set_count(SPI, len);
	// 开启DMA_DRQ
	sys_spi_enable_drq(SPI, 1, 1);
	// 片选使能
	// sys_spi_select(SPI);
	// SPI开始
	sys_spi_start(SPI);
	//----
	// sysprintf("等待发送 \r\n");
	while (1)
	{
		if (DMA_Get_Full_TIP(RXdma))
		{
			// sysprintf("发送数据完成...\r\n");
			break;
		}
		// 延时或作务
		spi_dma_delay();
	}
	DMA_Disable(RXdma);
	DMA_Disable(TXdma);
	// 写通CACHE
	//	sysInvalidCache();
	sysFlushCache(D_CACHE);
	// 片选失能
	//	sys_spi_deselect(SPI);
	//--
	return 0;
}
#endif

/*SPI传输
 */
int sys_spi_transfer(int SPI, void *txbuf, void *rxbuf, int len)
{
#if SPI_DMA_EN
	void *p = 0;
	if (len > 64) //>64 DMA模式-DMA模式时缓存指针不能为0
	{
		if (txbuf == NULL)
		{
			p = spi_malloc(len);
			if (p == 0)
			{
				sysprintf("ERR:spi_malloc() txbuf==0 \r\n");
				return 0;
			}
			txbuf = p;
		}
		if (rxbuf == NULL)
		{
			p = spi_malloc(len);
			if (p == 0)
			{
				sysprintf("ERR:spi_malloc() rxbuf==0 \r\n");
				return 0;
			}
			rxbuf = p;
		}
		if (((int)txbuf % 4) != 0) // DMA缓存需要4字节对齐
		{
			sysprintf("ERR:spi_malloc() txbuf alignment(%08x)\r\n", txbuf);
			return 0;
		}
		if (((int)rxbuf % 4) != 0) // DMA缓存需要4字节对齐
		{
			sysprintf("ERR:spi_malloc() rxbuf alignment(%08x)\r\n", rxbuf);
			return 0;
		}

		sys_spi_dma_transfer(SPI, SPI_TXdma, SPI_RXdma, txbuf, rxbuf, len);
		if (p)
			spi_free(p);
	}
	else // CPU模式
	{
#endif
		sys_spi_cpu_transfer(SPI, txbuf, rxbuf, len);
#if SPI_DMA_EN
	}
#endif
	return len;
}

/*SPI write_then_read
 */
static int sys_spi_write_then_read(int SPI, void *txbuf, int txlen, void *rxbuf, int rxlen)
{

	if (sys_spi_transfer(SPI, txbuf, NULL, txlen) != txlen)
		return -1;
	if (sys_spi_transfer(SPI, NULL, rxbuf, rxlen) != rxlen)
		return -1;
	return 0;
}
/*SPI write_then_write
 */
static int sys_spi_write_then_write(int SPI, void *txbuf0, int txlen0, void *txbuf1, int txlen1)
{
	if (sys_spi_transfer(SPI, txbuf0, NULL, txlen0) != txlen0)
		return -1;
	if (sys_spi_transfer(SPI, txbuf1, NULL, txlen1) != txlen1)
		return -1;
	return 0;
}

/*SPI IO初始化
 */
void spi_gpio_init(int SPI)
{
	int i = 0;
	if (SPI == SPI0)
	{
		for (i = 0; i < 4; i++)
		{
			GPIO_Congif(GPIOC, GPIO_Pin_0 + i, GPIO_Mode_010, GPIO_PuPd_NOPULL);
			GPIO_Multi_Driving(GPIOC, GPIO_Pin_0 + i, 3); // 增加驱动力
		}
	}
	else if (SPI == SPI1)
	{
		for (i = 0; i < 4; i++)
		{
			GPIO_Congif(GPIOE, GPIO_Pin_7 + i, GPIO_Mode_100, GPIO_PuPd_NOPULL);
			GPIO_Multi_Driving(GPIOE, GPIO_Pin_7 + i, 3); // 增加驱动力
		}
	}
}
/*SPI clock_初始化
 */
void spi_clock_init(int SPI)
{
	S_BIT(0x01c202c0, (20 + SPI)); /* Deassert reset */
	S_BIT(0x01c20060, (20 + SPI)); /* Open the bus gate */
}

/*SPI初始化
 */
void spi_flash_init(int SPI)
{
	spi_gpio_init(SPI);
	spi_clock_init(SPI);
	spi_spi_confing(SPI);
}
//--------------------------------------------------------------------------------------------------------
//--------------------------------------W25Q128读写------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------
int addr_mode = 0; // 地址模式-【默认0=3位地址】【1=4位地址】-大于16MB时使用4位地址
#define W25Q256_Enter_4_Addres 0xB7
#define W24Q256_Exit_4_Addres 0xE9

/***********************************************
Reg0
	//BIT7  6   5   4   3   2   1   0
	//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
	//SPR:默认0,状态寄存器保护位,配合WP使用
	//TB,BP2,BP1,BP0:FLASH区域写保护设置
	//WEL:写使能锁定
	//BUSY:忙标记位(1,忙;0,空闲)
	//默认:0x00
***********************************************/
/***********************************************
Reg1
	//BIT7  6   5   4   3   2   1   0
	//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
	//SPR:默认0,状态寄存器保护位,配合WP使用
	//TB,BP2,BP1,BP0:FLASH区域写保护设置
	//WEL:写使能锁定
	//BUSY:忙标记位(1,忙;0,空闲)
	//默认:0x00
***********************************************/
/***********************************************
Reg3
	//BIT7  6   5   4   3   2   1   0
	// (R) DRV1 DRV0(R)(R) WPS ADP ADS
  //  ADS=地址模式位 默认0   1=4位地址，否则3位地址 16MB以上型号会使用
***********************************************/

// 读取SPI_FLASH的状态寄存器
u8 SPI_Flash_ReadSR(int SPI, char Reg)
{
	u8_t addr_buff[4];
	u8 buf;
	volatile int res = 0;
	addr_buff[0] = Reg;
	sys_spi_select(SPI);
	if (sys_spi_write_then_read(SPI, addr_buff, 1, (void *)&buf, 1) < 0)
		res = -1;
	sys_spi_deselect(SPI);
	return buf;
}

// 等待空闲
void SPI_Flash_Wait_Busy(int SPI)
{
	while ((SPI_Flash_ReadSR(SPI, W25X_ReadStatusReg1) & 0x01) == 0x01)
		; // 等待BUSY位清空，最低位为空闲位
}
// SPI_FLASH写使能
// 将WEL置位
int SPI_FLASH_Write_Enable(int SPI)
{
	u8_t addr_buff[4];
	int res = 0;
	addr_buff[0] = W25X_WriteEnable;
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, 1) != 1)
		res = -1;
	sys_spi_deselect(SPI);
	return res;
}
// SPI_FLASH写禁止
// 将WEL清零
int SPI_FLASH_Write_Disable(int SPI)
{
	u8_t addr_buff[4];
	int res = 0;
	addr_buff[0] = W25X_WriteDisable;
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, 1) != 1)
		res = -1;
	sys_spi_deselect(SPI);
	return res;
}
/*擦除
 */
int SPI_Flash_Erase_Sector(int SPI, int addr)
{
	u8_t addr_buff[5];
	int buff_len = 0;
	int res = 0;
	if (addr_mode == 0) // 3地址
	{
		addr_buff[0] = 0x20;
		addr_buff[1] = (u8_t)(addr >> 16);
		addr_buff[2] = (u8_t)(addr >> 8);
		addr_buff[3] = (u8_t)(addr >> 0);
		buff_len = 4;
	}
	else // 4地址
	{
		addr_buff[0] = 0x21;
		addr_buff[1] = (u8_t)(addr >> 24);
		addr_buff[2] = (u8_t)(addr >> 16);
		addr_buff[3] = (u8_t)(addr >> 8);
		addr_buff[4] = (u8_t)(addr >> 0);
		buff_len = 5;
	}
	// 写使能
	if (SPI_FLASH_Write_Enable(SPI) < 0)
		res = -1;
	SPI_Flash_Wait_Busy(SPI);
	// 擦除
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, buff_len) != buff_len)
		res = -1;
	sys_spi_deselect(SPI);

	SPI_Flash_Wait_Busy(SPI);

	return res;
}
/*擦除32K块-不支持4位地址
 */
int SPI_Flash_Erase_Block32K(int SPI, int addr)
{
	u8_t addr_buff[4];
	int res = 0;
	if (addr_mode == 1) // 4地址
	{
		sysprintf("ERR:Flash_Erase_Block32K 4 addresses are not supported!!!\r\n");
		return -1;
	}
	addr_buff[0] = 0x52;
	addr_buff[1] = (u8_t)(addr >> 16);
	addr_buff[2] = (u8_t)(addr >> 8);
	addr_buff[3] = (u8_t)(addr >> 0);

	// 写使能
	if (SPI_FLASH_Write_Enable(SPI) < 0)
		res = -1;
	SPI_Flash_Wait_Busy(SPI);
	// 擦除
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, 4) != 4)
		res = -1;
	sys_spi_deselect(SPI);

	SPI_Flash_Wait_Busy(SPI);

	return res;
}
/*擦除64K块
 */
int SPI_Flash_Erase_Block64K(int SPI, int addr)
{
	u8_t addr_buff[5];
	int buff_len = 0;
	int res = 0;
	if (addr_mode == 0) // 3地址
	{
		addr_buff[0] = 0xD8;
		addr_buff[1] = (u8_t)(addr >> 16);
		addr_buff[2] = (u8_t)(addr >> 8);
		addr_buff[3] = (u8_t)(addr >> 0);
		buff_len = 4;
	}
	else // 4地址
	{
		addr_buff[0] = 0xDC;
		addr_buff[1] = (u8_t)(addr >> 24);
		addr_buff[2] = (u8_t)(addr >> 16);
		addr_buff[3] = (u8_t)(addr >> 8);
		addr_buff[4] = (u8_t)(addr >> 0);
		buff_len = 5;
	}
	// 写使能
	if (SPI_FLASH_Write_Enable(SPI) < 0)
		res = -1;
	SPI_Flash_Wait_Busy(SPI);
	// 擦除
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, buff_len) != buff_len)
		res = -1;
	sys_spi_deselect(SPI);

	SPI_Flash_Wait_Busy(SPI);

	return res;
}
/*读UID 64Bit 8Byte
 */
int SPI_Flash_Read_UID(int SPI, unsigned char *rbuff)
{
	u8_t wbuff[5];
	int res = 0;
	wbuff[0] = 0x4B;
	wbuff[1] = 0x0;
	wbuff[2] = 0x0;
	wbuff[3] = 0x0;
	wbuff[4] = 0x0;
	// 命令
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, wbuff, NULL, 5) != 5)
		res = -1;
	if (sys_spi_transfer(SPI, NULL, rbuff, 8) != 8)
		res = -1;
	sys_spi_deselect(SPI);

	SPI_Flash_Wait_Busy(SPI);

	return res;
}
// 读设备ID
unsigned char spi_nor_flash_read_device_id(int SPI)
{
	u8_t addr_buff[4];
	u8_t buf[4];
	unsigned char device_id = 0;

	addr_buff[0] = 0xAB;
	sys_spi_select(SPI);
	if (sys_spi_write_then_read(SPI, addr_buff, 1, &buf, 4) < 0)
		device_id = 0;
	sys_spi_deselect(SPI);
	device_id = buf[3];
	return device_id;
}

/*
进入4字节地址模式-容量读写大于16MB需要改为4字节地址模式
*/
int spi_flash_enable_4_addres(int SPI)
{
	volatile int res = 0;
	u8_t addr_buff[4];
	addr_buff[0] = W25Q256_Enter_4_Addres;
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, 1) != 1)
		res = -1;
	sys_spi_deselect(SPI);
	// 判断是不是进入了4位地址模式
	if ((SPI_Flash_ReadSR(SPI, W25X_ReadStatusReg3) & 0x01) == 0x01)
	{
		addr_mode = 1; // 4字节地址模式
		// sysprintf("enable 4 addr mode!!!\r\n");
		return 0;
	}
	else
	{
		sysprintf("ERR: enable 4 addr mode!!!\r\n");
		return -1;
	}
}
/*
退出4字节地址模式-容量读写大于16MB需要改为4字节地址模式
*/
int spi_flash_disable_4_addres(int SPI)
{
	volatile int res = 0;
	u8_t addr_buff[4];
	if (addr_mode == 0)
	{
		sysprintf("ERR:Current 3 addr mode!!!\r\n");
		return -1;
	}
	addr_buff[0] = W24Q256_Exit_4_Addres;
	sys_spi_select(SPI);
	if (sys_spi_transfer(SPI, addr_buff, NULL, 1) != 1)
		res = -1;
	sys_spi_deselect(SPI);

	// 判断是不是进入了4位地址模式
	if ((SPI_Flash_ReadSR(SPI, W25X_ReadStatusReg3) & 0x01) == 0x00)
	{
		addr_mode = 0; // 3字节地址模式
		// sysprintf("disable 4 addr mode!!!\r\n");
		return 0;
	}
	else
	{
		sysprintf("ERR: disable 4 addr mode!!!\r\n");
		return -1;
	}
}
/*SPI读
 */
int sys_spi_flash_read(int SPI, int addr, void *buf, int count)
{
	u8_t addr_buff[5];
	int buff_len = 0;
	int res = 0;
	if (addr_mode == 0) // 3地址
	{
		addr_buff[0] = W25X_ReadData;
		addr_buff[1] = (u8_t)(addr >> 16);
		addr_buff[2] = (u8_t)(addr >> 8);
		addr_buff[3] = (u8_t)(addr >> 0);
		buff_len = 4;
	}
	else // 4地址
	{
		addr_buff[0] = W25X_ReadData_4ADDR; // 0x13
		addr_buff[1] = (u8_t)(addr >> 24);
		addr_buff[2] = (u8_t)(addr >> 16);
		addr_buff[3] = (u8_t)(addr >> 8);
		addr_buff[4] = (u8_t)(addr >> 0);
		buff_len = 5;
	}
	sys_spi_select(SPI);
	if (sys_spi_write_then_read(SPI, addr_buff, buff_len, buf, count) < 0)
		res = -1;
	sys_spi_deselect(SPI);
	return res;
}

/*SPI写
 */
int sys_spi_flash_write(int SPI, int addr, void *buf, int count)
{
	u8_t addr_buff[5];
	int buff_len = 0;
	int res = 0;
	if (addr_mode == 0) // 3地址
	{
		addr_buff[0] = W25X_PageProgram;
		addr_buff[1] = (u8_t)(addr >> 16);
		addr_buff[2] = (u8_t)(addr >> 8);
		addr_buff[3] = (u8_t)(addr >> 0);
		buff_len = 4;
	}
	else // 4地址
	{
		addr_buff[0] = W25X_PageProgram_4ADDR; // 0x12
		addr_buff[1] = (u8_t)(addr >> 24);
		addr_buff[2] = (u8_t)(addr >> 16);
		addr_buff[3] = (u8_t)(addr >> 8);
		addr_buff[4] = (u8_t)(addr >> 0);
		buff_len = 5;
	}
	// 写使能
	if (SPI_FLASH_Write_Enable(SPI) < 0)
		res = -1;
	SPI_Flash_Wait_Busy(SPI);
	// 写
	sys_spi_select(SPI);
	if (sys_spi_write_then_write(SPI, addr_buff, buff_len, buf, count) < 0)
		res = -1;
	sys_spi_deselect(SPI);
	SPI_Flash_Wait_Busy(SPI);
	return res;
}
// 无检验写SPI FLASH
// 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
// 具有自动换页功能
// 在指定地址开始写入指定长度的数据,但是要确保地址不越界!
// pBuffer:数据存储区
// WriteAddr:开始写入的地址(24bit)
// NumByteToWrite:要写入的字节数(最大65535)
// CHECK OK
void SPI_Flash_Write_NoCheck(int SPI, u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
	u16 pageremain;
	pageremain = 256 - WriteAddr % 256; // 单页剩余的字节数
	if (NumByteToWrite <= pageremain)
		pageremain = NumByteToWrite; // 不大于256个字节
	while (1)
	{
		sys_spi_flash_write(SPI, WriteAddr, (void *)pBuffer, pageremain);
		if (NumByteToWrite == pageremain)
			break; // 写入结束了
		else	   // NumByteToWrite>pageremain
		{
			pBuffer += pageremain;	 // 加上前一页的写和数量得到下页写数据的开始
			WriteAddr += pageremain; // 加上前一页的写的地此得到下页写地此的开始

			NumByteToWrite -= pageremain; // 减去已经写入了的字节数
			if (NumByteToWrite > 256)
				pageremain = 256; // 一次可以写入256个字节
			else
				pageremain = NumByteToWrite; // 不够256个字节了，，，，，
		}
	}
}
// 带擦除操作的写FLASH
// 在指定地址开始写入指定长度的数据
// pBuffer:数据存储区
// WriteAddr:开始写入的地址(24bit)
// NumByteToWrite:要写入的字节数(最大65535)
__align(4) u8 SPI_FLASH_BUF[4096];
void SPI_Flash_Write(int SPI, unsigned char *pBuffer, unsigned int WriteAddr, unsigned int NumByteToWrite)
{
	u32 secpos;
	u16 secoff;
	u16 secremain;
	u16 i;

	secpos = WriteAddr / 4096; // 扇区地址 0~511 for w25x16 ，4K一个扇区
	secoff = WriteAddr % 4096; // 在扇区内的偏移
	secremain = 4096 - secoff; // 扇区空间大小

	if (NumByteToWrite <= secremain)
		secremain = NumByteToWrite; // 不大于4096个字节，小于一个扇区时得到剩余空间
	while (1)
	{
		// SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
		sys_spi_flash_read(SPI, secpos * 4096, (void *)SPI_FLASH_BUF, 4096);
		for (i = 0; i < secremain; i++) // 校验数据
		{
			if (SPI_FLASH_BUF[secoff + i] != 0XFF)
				break; // 判断是否需要擦除
		}

		if (i < secremain) // 需要擦除
		{
			SPI_Flash_Erase_Sector(SPI, secpos * 4096); // 擦除这个扇区 W25Q128要x4096
			for (i = 0; i < secremain; i++)				// 复制
			{
				SPI_FLASH_BUF[i + secoff] = pBuffer[i]; // 把数据复制到一个扇区的剩余空间，
			}
			SPI_Flash_Write_NoCheck(SPI, SPI_FLASH_BUF, secpos * 4096, 4096); // 写入整个扇区 ，以便前面擦除的的数据能还原
		}
		else
			SPI_Flash_Write_NoCheck(SPI, pBuffer, WriteAddr, secremain); // 写已经擦除了的,直接写入扇区剩余区间.

		if (NumByteToWrite == secremain)
			break; // 写入结束了
		else	   // 写入未结束
		{
			secpos++;	// 扇区地址增1
			secoff = 0; // 第二次写入时，偏移位置为0

			pBuffer += secremain;		 // 指针偏移
			WriteAddr += secremain;		 // 写地址偏移
			NumByteToWrite -= secremain; // 字节数递减
			if (NumByteToWrite > 4096)
				secremain = 4096; // 下一个扇区还是写不完
			else
				secremain = NumByteToWrite; // 下一个扇区可以写完了
		}
	}
}
#ifdef SPI_W25Q128_TESE
/****************************************************
W25Q128_spi测试
SPI 数据小于等于64Byte时使用CPU模式，SPI 数据大于64Byte时使用DMA模式;
sys_spi_transfer里面也可改成单CPU模式或单DMA模式;
测试SPI-FLASH使用板上存储程序的SPI-FLASH，测试起始地址不能为程序区;
****************************************************/
#define TESTSIZE (8)
void W25Q128_Demo(void)
{
	unsigned char id_buff[8];
	int SPI = SPI0, i, s = 0, addr = (1024 * 1024 * 8);
	u8 buff_in[TESTSIZE];
	u8 buff_out[TESTSIZE];
#if SPI_DMA_EN
	DMA TXdma;
	DMA RXdma;
	SPI_TXdma = &TXdma;
	SPI_RXdma = &RXdma;
#endif
	/*------数据初始化------*/
	for (i = 0; i < TESTSIZE; i++)
	{
		buff_in[i] = i & 0xff;
		buff_out[i] = 0;
	}
	/*------SPI初始化------*/
	sysprintf("SPI_Demo W25Q128...\r\n");
	sysprintf("SPI%d_Init...\r\n", SPI);
	spi_flash_init(SPI);
	char did = spi_nor_flash_read_device_id(SPI);
	if (did > 0x17) // 容量大于16MB，设置为4字节地址模式，设备ID=0x17为W25Q128(16MB)
	{
		spi_flash_enable_4_addres(SPI);
		sysprintf("addr=4byte\r\n");
	}
	SPI_Flash_Read_UID(SPI0, id_buff);
	sysprintf("DID=%02X,UID:%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\r\n", did,
			  id_buff[0], id_buff[1], id_buff[2], id_buff[3], id_buff[4], id_buff[5], id_buff[6], id_buff[7]);
#if SPI_DMA_EN
	/*------DMA初始化------*/
	DMA_Init();
#endif
	/*------写入------*/
	sysprintf("SPI 写入...\r\n");
	SPI_Flash_Write(SPI, buff_in, addr, TESTSIZE);
	/*------读出------*/
	sysprintf("SPI_读出...\r\n");
	sys_spi_flash_read(SPI, addr, buff_out, TESTSIZE);
	/*------校验------*/
	for (i = 0; i < TESTSIZE; i++)
	{
		sysprintf("read[%d]:[%d]-[%d]\r\n", i, buff_in[i], buff_out[i]);
		if (buff_in[i] == buff_out[i])
			s++;
	}
	if (s == TESTSIZE)
		sysprintf("读写正确\r\n");
	else
		sysprintf("读写错误\r\n");
	// 退出4字节地址模式
	if (addr_mode == 1)
		spi_flash_disable_4_addres(SPI);
	while (1)
		;
}

#endif
